import sys
import unittest
from collections import deque

from byte_buffer import IByteBuffer


class ListWriteByteBuffer(IByteBuffer):
    def __init__(self):
        self.__bytes_list = deque()
        self.__reader_index = 0
        self.__size = 0

    def write_bytes(self, bytes_data):
        if not isinstance(bytes_data, bytes):
            raise TypeError(f'bytes_data({type(bytes_data)} must be bytes)')

        self.__bytes_list.append(bytes_data)
        self.__size += len(bytes_data)

    def read_bytes(self, size):
        if size <= 0:
            raise ValueError('size can not be less than 0')

        ret_bytes = bytes()
        if len(self.__bytes_list) == 0:
            return ret_bytes

        while len(self.__bytes_list) > 0:
            curr_bytes_end = len(self.__bytes_list[0])
            read_end = size - len(ret_bytes) + self.__reader_index

            if read_end < curr_bytes_end:
                ret_bytes += self.__bytes_list[0][self.__reader_index:read_end]
                self.__size -= (read_end - self.__reader_index)
                self.__reader_index = read_end
                return ret_bytes

            ret_bytes += self.__bytes_list[0][self.__reader_index:curr_bytes_end]
            self.__bytes_list.popleft()
            self.__size -= (curr_bytes_end - self.__reader_index)
            self.__reader_index = 0

            if read_end == curr_bytes_end:
                return ret_bytes
            else:
                continue

        return ret_bytes

    def memoryview(self):
        if len(self.__bytes_list) > 0:
            return memoryview(self.__bytes_list[0])[self.__reader_index:]

    def skip_bytes(self, size):
        if size <= 0:
            raise ValueError('size can not be less than 0')

        if len(self.__bytes_list) == 0:
            return

        skip_len = 0
        while len(self.__bytes_list) > 0:
            curr_bytes_end = len(self.__bytes_list[0])
            read_end = size - skip_len + self.__reader_index

            if read_end < curr_bytes_end:
                self.__size -= (read_end - self.__reader_index)
                self.__reader_index = read_end
                return

            self.__bytes_list.popleft()
            curr_left = curr_bytes_end - self.__reader_index
            self.__size -= curr_left
            skip_len += curr_left
            self.__reader_index = 0

            if read_end == curr_bytes_end:
                return
            else:
                continue

    def capacity(self):
        return self.__size + self.__reader_index

    def readable_bytes(self):
        return self.__size

    def writable_bytes(self):
        return sys.maxsize

    def is_readable(self):
        return self.__size > 0

    def is_readable_size(self, size):
        return self.__size >= size

    def is_writable(self):
        return True

    def is_writable_size(self, size):
        return True

    def clear(self):
        self.__bytes_list.clear()
        self.__reader_index = 0
        self.__size = 0

    def reader_index(self):
        return self.__reader_index

    def writer_index(self):
        return self.capacity()

    def _str_internal(self):
        return (f"capacity:{self.capacity()}, read_index:{self.__reader_index}, "
                f"data len:{self.readable_bytes()}, deque len:{len(self.__bytes_list)}")

    def __str__(self):
        return self._str_internal()


class ListWriteByteBufferTestCase(unittest.TestCase):
    def setUp(self):
        self.buf = ListWriteByteBuffer()

    def tearDown(self):
        del self.buf

    def test_write_read(self):
        self.buf.write_bytes(b'0123456')
        self.assertEqual(7, self.buf.capacity())
        self.buf.write_bytes(b'0123456789')
        self.assertEqual(17, self.buf.capacity())

        self.assertEqual(b'0123', self.buf.read_bytes(4))
        self.assertEqual(4, self.buf.reader_index())
        self.assertEqual(17, self.buf.capacity())
        self.assertEqual(13, self.buf.readable_bytes())

        self.assertEqual(b'456012', self.buf.read_bytes(6))
        self.assertEqual(3, self.buf.reader_index())
        self.assertEqual(10, self.buf.capacity())
        self.assertEqual(7, self.buf.readable_bytes())

        self.assertEqual(b'3456789', self.buf.read_bytes(10))
        self.assertEqual(0, self.buf.reader_index())
        self.assertEqual(0, self.buf.capacity())
        self.assertEqual(0, self.buf.readable_bytes())

    def test_skip(self):
        self.buf.write_bytes(b'01234568')
        self.assertEqual(8, self.buf.capacity())
        self.buf.write_bytes(b'0123456789')
        self.assertEqual(18, self.buf.capacity())

        self.buf.skip_bytes(5)
        self.assertEqual(5, self.buf.reader_index())
        self.assertEqual(18, self.buf.capacity())
        self.assertEqual(13, self.buf.readable_bytes())

        self.buf.skip_bytes(5)
        self.assertEqual(2, self.buf.reader_index())
        self.assertEqual(10, self.buf.capacity())
        self.assertEqual(8, self.buf.readable_bytes())

        self.buf.skip_bytes(20)
        self.assertEqual(0, self.buf.reader_index())
        self.assertEqual(0, self.buf.readable_bytes())
        self.assertEqual(0, self.buf.capacity())

    def test_mem_view(self):
        self.buf.write_bytes(b'01234567')
        self.buf.write_bytes(b'0123456789')

        self.assertEqual(b'01234567', self.buf.memoryview())

        self.buf.skip_bytes(4)
        self.assertEqual(b'4567', self.buf.memoryview())

        self.buf.skip_bytes(8)
        self.assertEqual(b'456789', self.buf.memoryview())
